﻿using System;
using Microsoft.Kinect;
using Kinect.Gesture;


namespace Kinect.Toolbox
{
    public class SwipeGestureDetector : GestureDetector
    {
        public float SwipeMinimalLength {get;set;}
        public float SwipeMaximalHeight {get;set;}
        public int SwipeMininalDuration { get; set; }
        public int SwipeMaximalDuration { get; set; }


        public SwipeGestureDetector(int windowSize = 20)
            : base(windowSize)
        {
            SwipeMinimalLength = 0.4f;
            SwipeMaximalHeight = 0.2f;
            SwipeMininalDuration = 250;
            SwipeMaximalDuration = 1500;

        }

        /// <summary>
        /// 目前只判断了左手的挥动
        /// </summary>
        /// <param name="heightFunction"></param>
        /// <param name="directionFunction"></param>
        /// <param name="lengthFunction"></param>
        /// <param name="minTime"></param>
        /// <param name="maxTime"></param>
        /// <returns></returns>
        protected bool ScanPositions(Func<Vector3Struct, Vector3Struct, bool> heightFunction, Func<Vector3Struct, Vector3Struct, bool> directionFunction, 
            Func<Vector3Struct, Vector3Struct, bool> lengthFunction, int minTime, int maxTime)
        {
            int start = 0;
            
            for (int index = 1; index < Entries.Count - 1; index++)
            {
                Skeleton firstSkeleton = Entries[0].Skeleton;
                SkeletonPoint firstLeftHand = firstSkeleton.Joints[JointType.HandLeft].Position,
                    firstRightHand = firstSkeleton.Joints[JointType.HandRight].Position;
                Vector3Struct firstLeftVec3 = firstLeftHand.ToVector3(),
                    firstRightVec3 = firstRightHand.ToVector3();

                Skeleton scanSkeleton = Entries[index].Skeleton;
                Vector3Struct scanLeftVec3 = scanSkeleton.Joints[JointType.HandLeft].Position.ToVector3(),
                    scanRightVec3 = scanSkeleton.Joints[JointType.HandRight].Position.ToVector3();

                Skeleton nextScanSkeleton = Entries[index + 1].Skeleton;
                Vector3Struct nextScanLeftVec3 = nextScanSkeleton.Joints[JointType.HandLeft].Position.ToVector3(),
                    nextScanRightVec3 = nextScanSkeleton.Joints[JointType.HandRight].Position.ToVector3();
                // 去除不在同一方向上的点，即判断左右挥手时，排除斜着挥动的点
                if (!heightFunction(firstLeftVec3, scanLeftVec3) || !directionFunction(scanLeftVec3, nextScanLeftVec3))
                {
                    start = index;
                }
                Skeleton startAvailableSkeleton = Entries[start].Skeleton;
                Vector3Struct startAvailableLeftVec3 = startAvailableSkeleton.Joints[JointType.HandLeft].Position.ToVector3();

                //排除位置过于移动缓慢的点对整个姿势的判断
                if (lengthFunction(scanLeftVec3, startAvailableLeftVec3))
                {
                    double totalMilliseconds = (Entries[index].Time - Entries[start].Time).TotalMilliseconds;
                    if (totalMilliseconds >= minTime && totalMilliseconds <= maxTime)
                    {
                        return true;
                    }
                }
            }

            return false;
        }


        protected override void LookForGesture()
        {
            // Swipe to right
            if (ScanPositions((p1, p2) => Math.Abs(p2.Y - p1.Y) < SwipeMaximalHeight && Math.Abs(p2.Z - p1.Z) < SwipeMaximalHeight, // Height
                (p1, p2) => p2.X - p1.X > -0.01f, // Progression to right
                (p1, p2) => Math.Abs(p2.X - p1.X) > SwipeMinimalLength, // Length
                SwipeMininalDuration, SwipeMaximalDuration)) // Duration
            {
                RaiseGestureDetected(new GestureEventArgs(E_GestureDescrition.SwipeToRight,JointType.HandLeft) );
                return;
            }

            // Swipe to up
            if (ScanPositions((p1, p2) => Math.Abs(p2.X - p1.X) < SwipeMaximalHeight && Math.Abs(p2.Z - p1.Z) < SwipeMaximalHeight, // Height
                (p1, p2) => p2.Y - p1.Y > -0.01f, // Progression to right
                (p1, p2) => Math.Abs(p2.Y - p1.Y) > SwipeMinimalLength, // Length
                SwipeMininalDuration, SwipeMaximalDuration)) // Duration
            {
                RaiseGestureDetected(new GestureEventArgs(E_GestureDescrition.SwipeToUp,JointType.HandLeft) );

                return;
            }

            // Swipe to left
            if (ScanPositions((p1, p2) => Math.Abs(p2.Y - p1.Y) < SwipeMaximalHeight && Math.Abs(p2.Z - p1.Z) < SwipeMaximalHeight,  // Height
                (p1, p2) => p2.X - p1.X < 0.01f, // Progression to right
                (p1, p2) => Math.Abs(p2.X - p1.X) > SwipeMinimalLength, // Length
                SwipeMininalDuration, SwipeMaximalDuration))// Duration
            {
                RaiseGestureDetected(new GestureEventArgs(E_GestureDescrition.SwipeToLeft, JointType.HandLeft) );
                return;
            }

            // Swipe to down
            if (ScanPositions((p1, p2) => Math.Abs(p2.X - p1.X) < SwipeMaximalHeight && Math.Abs(p2.Z - p1.Z) < SwipeMaximalHeight,  // Height
                (p1, p2) => p2.Y - p1.Y < 0.01f, // Progression to right
                (p1, p2) => Math.Abs(p2.Y - p1.Y) > SwipeMinimalLength, // Length
                SwipeMininalDuration, SwipeMaximalDuration))// Duration
            {
                RaiseGestureDetected(new GestureEventArgs(E_GestureDescrition.SwipeToDown,JointType.HandLeft) );
                return;
            }

        }
    }
}